<?php

declare(strict_types=1);

namespace Zlf\AppValidate\Rule;

use Zlf\Unit\Is;
use Zlf\Unit\Number;

/**
 * 金额验证器
 * 用于验证输入值是否为有效的金额，并支持设置最小值和最大值限制。
 */
class MoneyValidate extends RuleAbstract
{
    /**
     * 默认错误消息
     * 当输入值不是有效金额时返回的错误信息。
     * @var string
     */
    protected $_error = '{label}不是有效的金额';

    /**
     * 最小值限制
     * 金额的最小值，默认为 0。
     * @var float|int|null
     */
    protected $_min = 0;

    /**
     * 最小值错误提示
     * 当输入值小于最小值时返回的错误信息。
     * @var string
     */
    protected $_minError = "{label}不能小于{min}";

    /**
     * 最大值限制
     * 金额的最大值，默认为 null（无限制）。
     * @var int|float|null
     */
    protected $_max = null;

    /**
     * 最大值错误提示
     * 当输入值大于最大值时返回的错误信息。
     * @var string
     */
    protected $_maxError = "{label}不能大于{max}";

    /**
     * 设置金额的最大值限制
     * @param int|float $max 最大值
     * @return $this
     */
    public function setMax($max): MoneyValidate
    {
        $this->_max = $max;
        return $this;
    }

    /**
     * 设置最大值错误提示
     * @param string $maxError 自定义最大值错误提示
     * @return $this
     */
    public function setMaxError(string $maxError): MoneyValidate
    {
        $this->_maxError = $maxError;
        return $this;
    }

    /**
     * 设置金额的最小值限制
     * @param int|float $min 最小值
     * @return $this
     */
    public function setMin($min): MoneyValidate
    {
        $this->_min = $min;
        return $this;
    }

    /**
     * 设置最小值错误提示
     * @param string $minError 自定义最小值错误提示
     * @return $this
     */
    public function setMinError(string $minError): MoneyValidate
    {
        $this->_minError = $minError;
        return $this;
    }

    /**
     * 验证金额
     * 验证输入值是否为有效的金额，并检查是否满足最小值和最大值限制。
     * @param mixed $value 输入值
     * @param string $label 验证名（用于错误信息中）
     * @return bool 验证结果
     */
    public function validate($value, string $label = ''): bool
    {
        // 确保输入值是数字类型
        if (is_numeric($value)) {
            // 如果值为空且 `_noSkipping` 为 true，则直接返回 true
            if (Is::empty($value) && $this->_noSkipping === true) {
                $this->_value = $value;
                return true;
            }

            // 格式化输入值为数字
            $num = Number::format($value);

            // 检查最小值限制
            if (is_int($this->_min) || is_float($this->_min)) {
                if ($num < $this->_min) {
                    $this->addError($this->_minError, $label);
                }
            }

            // 检查最大值限制
            if (is_int($this->_max) || is_float($this->_max)) {
                if ($num > $this->_max) {
                    $this->addError($this->_maxError, $label);
                }
            }

            // 检查金额的小数精度是否超过两位
            if (Number::precision($num) > 2) {
                $this->addError("{label}最多精确到分", $label);
            }

            // 如果有错误发生，返回 false
            if ($this->isFail()) {
                return false;
            }

            // 验证通过，保存验证结果并返回 true
            $this->_value = $value;
            return true;
        } elseif (is_string($value) && empty($value)) {// 如果输入值是空字符串且 `_noSkipping` 为 true，则直接返回 true
            if ($this->_noSkipping) {
                $this->_value = $value;
                return true;
            }
        }

        // 如果输入值无效，添加默认错误信息并返回 false
        $this->addError($this->_error, $label);
        return false;
    }
}
